package controller

import (
	"encoding/json"
	"fmt"
	"github.com/beego/beego/v2/server/web"
	"net/http"
	"scase.io/application-auto-scaling-service/pkg/api/errors"
	"scase.io/application-auto-scaling-service/pkg/api/model"
	"scase.io/application-auto-scaling-service/pkg/api/response"
	"scase.io/application-auto-scaling-service/pkg/api/validator"
	"scase.io/application-auto-scaling-service/pkg/common"
	"scase.io/application-auto-scaling-service/pkg/db"
	"scase.io/application-auto-scaling-service/pkg/service"
	"scase.io/application-auto-scaling-service/pkg/utils/logger"
)

type ECSController struct {
	web.Controller
}

func (c *ECSController) AddAgencyInfo() {
	tLogger := logger.GetTraceLogger(c.Ctx).WithField(logger.Stage, "add agency info")
	req := model.AddAgencyInfoReq{}
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(errors.RequestParseError))
		tLogger.Error("Read req body err: %+v", err)
		return
	}
	if err := validator.Validate(&req); err != nil {
		response.Error(c.Ctx, http.StatusBadRequest,
			errors.NewErrorRespWithMessage(errors.RequestParamsError, err.Error()))
		tLogger.Error("The request parameter is err: %+v", err)
		return
	}
	err := db.AddOrUpdateAgencyInfo(service.ConvertAgencyInfo(req))
	if err != nil {
		tLogger.Error("add agency error:%+v", err)
		response.Error(c.Ctx, http.StatusInternalServerError, err)
		return
	}
	response.Success(c.Ctx, http.StatusOK, nil)
}

func (c *ECSController) CreatePrePaidECSGroup() {
	tLogger := logger.GetTraceLogger(c.Ctx).WithField(logger.Stage, "create ecs group")
	projectId := c.GetString(urlParamProjectId)
	if errCode := validator.ErrCodeForProjectId(projectId); errCode != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(*errCode))
		tLogger.Error("project_id verification is failed,err: %s", errCode.Msg())
		return
	}
	req := model.CreateScalingGroupReq{}
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(errors.RequestParseError))
		tLogger.Error("Read req body err: %+v", err)
		return
	}
	tLogger.Info("Received ecs scaling group create request: %s", string(c.Ctx.Input.RequestBody))
	if err := validator.Validate(&req); err != nil {
		response.Error(c.Ctx, http.StatusBadRequest,
			errors.NewErrorRespWithMessage(errors.RequestParamsError, err.Error()))
		tLogger.Error("The request parameter is err: %+v", err)
		return
	}
	s := service.NewCreateEcsGroupService(c.Ctx, tLogger)
	resp, err := s.CreatePrepaidECSGroup(projectId, req)
	if err != nil {
		tLogger.Error("Create ECS error:%+v", err)
		response.Error(c.Ctx, http.StatusInternalServerError, err.ErrMsg)
		return
	}
	response.Success(c.Ctx, http.StatusOK, resp)
}

func (c *ECSController) UpdatePrePaidECSGroup() {
	tLogger := logger.GetTraceLogger(c.Ctx).WithField(logger.Stage, "update ecs group")
	groupId := c.GetString(urlParamScalingGroupId)
	projectId := c.GetString(urlParamProjectId)
	if errCode := validator.ErrCodeForProjectId(projectId); errCode != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(*errCode))
		tLogger.Error("project_id verification is failed,err: %s", errCode.Msg())
		return
	}
	req := model.UpdateScalingGroupReq{}
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(errors.RequestParseError))
		tLogger.Error("Read req body err: %+v", err)
		return
	}
	tLogger.Info("Received update request for update scaling group[%s]: %s", groupId, string(c.Ctx.Input.RequestBody))
	if err := validator.Validate(&req); err != nil {
		response.Error(c.Ctx, http.StatusBadRequest,
			errors.NewErrorRespWithMessage(errors.RequestParamsError, err.Error()))
		tLogger.Error("The request parameter is err: %+v", err)
		return
	}
	group, err := db.GetScalingGroupById(projectId, groupId)
	if err != nil {
		tLogger.Error("get scaling group error: %+v", err)
		response.Error(c.Ctx, http.StatusInternalServerError, err)
		return
	}
	if group.InstanceType == common.InstanceTypeVM {
		s := service.NewCreateEcsGroupService(c.Ctx, tLogger)
		if err := s.UpdatePrePaidEcsGroup(projectId, groupId, req); err != nil {
			tLogger.Error("update scaling group error: %+v", err)
			response.Error(c.Ctx, http.StatusInternalServerError, err)
			return
		}
	} else if group.InstanceType == common.InstanceTypePod {
		s := service.NewCreatePodGroupService(c.Ctx, tLogger)
		if err := s.UpdatePodGroup(projectId, group, req); err != nil {
			tLogger.Error("update scaling group error: %+v", err)
			response.Error(c.Ctx, http.StatusInternalServerError, err)
			return
		}
	} else {
		tLogger.Error("update scaling group error: %+v", fmt.Errorf("invalid instance type:%s", group.InstanceType))
		response.Error(c.Ctx, http.StatusBadRequest, fmt.Errorf("invalid instance type:%s", group.InstanceType))
		return
	}

	response.Success(c.Ctx, http.StatusNoContent, nil)
}

func (c *ECSController) ListScalingGroup() {
	tLogger := logger.GetTraceLogger(c.Ctx).WithField(logger.Stage, "list_scaling_group")
	projectId := c.GetString(urlParamProjectId)
	if errCode := validator.ErrCodeForProjectId(projectId); errCode != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(*errCode))
		tLogger.Error("project_id verification is failed,err: %s", errCode.Msg())
		return
	}
	name := c.GetString(queryParamGroupName)
	if len(name) > common.MaxLengthOfParamName {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(errors.ScalingGroupNameError))
		tLogger.Error(errors.ScalingGroupNameError.Msg())
		return
	}
	limit, err := c.GetInt(queryParamLimit, common.MaxNumberOfParamLimit)
	if err != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(errors.QueryParamLimitError))
		tLogger.Error("The query param limit is invalid,err: %+v", err)
		return
	}
	if limit < 0 || limit > common.MaxNumberOfParamLimit {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(errors.QueryParamLimitError))
		tLogger.Error("The query param limit(%d) is invalid", limit)
		return
	}
	offset, err := c.GetInt(queryParamOffset, 0)
	if err != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(errors.QueryParamOffsetError))
		tLogger.Error("The query param offset is invalid,err: %+v", err)
		return
	}
	if offset < 0 || offset > common.MaxNumberOfParamOffset {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(errors.QueryParamOffsetError))
		tLogger.Error("The query param offset(%d) is invalid", offset)
		return
	}
	tLogger.Info("Received query request for list scaling group list")
	list, errResp := service.ListInstanceScalingGroup(tLogger, projectId, name, limit, offset)
	if errResp != nil {
		response.Error(c.Ctx, errResp.HttpCode, errResp)
		return
	}
	response.Success(c.Ctx, http.StatusOK, list)
}

// 删除伸缩组，伸缩组实例，实例配置，取消关联策略
func (c *ECSController) DeleteScalingGroup() {
	tLogger := logger.GetTraceLogger(c.Ctx).WithField(logger.Stage, "delete_scaling_group")
	projectId := c.GetString(urlParamProjectId)
	if errCode := validator.ErrCodeForProjectId(projectId); errCode != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(*errCode))
		tLogger.Error("project_id verification is failed,err: %s", errCode.Msg())
		return
	}
	groupId := c.GetString(urlParamScalingGroupId)
	tLogger.Info("Received delete request for delete scaling group[%s]", groupId)
	s := service.NewCreateEcsGroupService(c.Ctx, tLogger)

	if errMsg := s.DeleteScalingGroup(tLogger, projectId, groupId); errMsg != nil {
		response.Error(c.Ctx, errMsg.HttpCode, errMsg)
		return
	}
	response.Success(c.Ctx, http.StatusNoContent, nil)
}

// GetScalingGroup get instance scaling group detail
func (c *ECSController) GetScalingGroup() {
	tLogger := logger.GetTraceLogger(c.Ctx).WithField(logger.Stage, "get_scaling_group")
	projectId := c.GetString(urlParamProjectId)
	if errCode := validator.ErrCodeForProjectId(projectId); errCode != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(*errCode))
		tLogger.Error("project_id verification is failed,err: %s", errCode.Msg())
		return
	}
	groupID := c.GetString(urlParamScalingGroupId)
	tLogger.Info("Received query request for get scaling group[%s]", groupID)
	group, errResp := service.GetInstanceScalingGroup(tLogger, projectId, groupID)
	if errResp != nil {
		response.Error(c.Ctx, errResp.HttpCode, errResp)
		return
	}
	response.Success(c.Ctx, http.StatusOK, group)
}

func (c *ECSController) ListInstance() {
	tLogger := logger.GetTraceLogger(c.Ctx).WithField(logger.Stage, "list_instance")
	projectId := c.GetString(urlParamProjectId)
	if errCode := validator.ErrCodeForProjectId(projectId); errCode != nil {
		response.Error(c.Ctx, http.StatusBadRequest, errors.NewErrorResp(*errCode))
		tLogger.Error("project_id verification is failed,err: %s", errCode.Msg())
		return
	}
	fleetId := c.Ctx.Input.Query(common.FleetId)

	tLogger.Info("Received query request for fleet id[%s]", fleetId)
	s := service.NewCreateEcsGroupService(c.Ctx, tLogger)
	resp, err := s.ListInstance(fleetId)
	if err != nil {
		tLogger.Error("list instance of fleet [%s] error:%+v", fleetId, err)
		response.Error(c.Ctx, http.StatusInternalServerError, err)
		return
	}
	response.Success(c.Ctx, http.StatusOK, resp)
}
